﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using King.Engine.Core;
using Microsoft.Xna.Framework.Input;
using King.Engine.Components;
using Microsoft.Xna.Framework.Graphics;
using King.Engine.Content;

namespace King.Engine.GameObjects.Hud.Menu
{
    /// <summary>
    /// GUI object that displays a menu.
    /// </summary>
    public class Menu : GameObject
    {
        
        #region Fields

        private MenuTree _menuTree;

        private Label _lblMenuTitle;
        private Label[] _lblMenuItems;

        private float _drawDepth;
        private SpriteFont _spriteFont;

        private MenuLayout _layout;

        #endregion


        #region Properties

        #endregion


        #region Constructor

        static Menu()
        {
            var controls = new Dictionary<MenuControl, Keys>()
            {
                {MenuControl.Left, Keys.A},
                {MenuControl.Down, Keys.S},
                {MenuControl.Right, Keys.D},
                {MenuControl.Up, Keys.W},
                {MenuControl.Select, Keys.Enter},
                {MenuControl.Back, Keys.Escape}
            };

            Input<MenuControl>.Initialize(controls);
        }

        /// <summary>
        /// Create a Menu
        /// </summary>
        /// <param name="tree">The tree structure of the menu</param>
        /// <param name="drawDepth">The draw depth of the menu</param>
        /// <param name="spriteFontName">The name of the SpriteFont used for the menu's text</param>
        /// <param name="layout">The layout of how the menu is displayed</param>
        public Menu(MenuTree tree, float drawDepth, string spriteFontName, MenuLayout layout)
        {
            _layout = layout;

            _drawDepth = drawDepth;
            _menuTree = tree;
            _spriteFont = ContentLoader.Get<SpriteFont>(spriteFontName);
            Refresh();
        }

        #endregion


        #region Protected Methods
        
        protected override void UpdateBeforeComponents(GameTime gameTime)
        {
            var controlsTapped = Input<MenuControl>.ControlsTapped();

            bool needsRefresh = false;
            foreach (var control in controlsTapped)
            {
                _menuTree.OnInput(control);
                needsRefresh = true;
            }

            if (needsRefresh) Refresh();
        }

        #endregion


        #region Private Methods

        private void Refresh()
        {
            RemoveComponents<Label>();

            string menuTitle = _menuTree.CurrentText;
            string[] menuItems = _menuTree.Items;
            int itemCount = menuItems.Length;

            _lblMenuTitle = new Label(_spriteFont, _drawDepth)
            {
                Text = menuTitle,
                Location = _layout.TitleLocation,
                Color = _layout.TitleColor
            };

            int selectedIndex = _menuTree.SelectedIndex;
            _lblMenuItems = new Label[itemCount];
            for (int itemIndex = 0; itemIndex < itemCount; itemIndex++)
            {
                Vector2 location = _layout.FirstItemLocation + itemIndex * _layout.ItemSeparation;

                Label label = new Label(_spriteFont, _drawDepth)
                {
                    Location = location,
                    Text = menuItems[itemIndex],
                    Color = (itemIndex == selectedIndex) ? _layout.SelectedItemColor : _layout.ItemColor
                };

                _lblMenuItems[itemIndex] = label;
            }

            AddComponent(_lblMenuTitle);
            AddComponents(_lblMenuItems);
        }

        #endregion

    }

    /// <summary>
    /// The layout of how a menu is displayed
    /// </summary>
    public struct MenuLayout
    {
        /// <summary>
        /// Location of the menu's title, relative to the menu's bounds
        /// </summary>
        public Vector2 TitleLocation;

        /// <summary>
        /// Location of the first menu item, relative to the menu's bounds
        /// </summary>
        public Vector2 FirstItemLocation;

        /// <summary>
        /// Displacement between the start of each menu item
        /// </summary>
        public Vector2 ItemSeparation;

        /// <summary>
        /// Color of the title
        /// </summary>
        public Color TitleColor;

        /// <summary>
        /// Color of the deselected menu items
        /// </summary>
        public Color ItemColor;

        /// <summary>
        /// Color of the selected menu item
        /// </summary>
        public Color SelectedItemColor;
    }

}
